﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;

namespace DimensionsHelper.Common.Utils;

public static class TypeHelper
{
    /// <summary>
    ///     读取枚举类型的各个成员，<paramref name="enumType" />类型需要是Enum类型。
    /// </summary>
    /// <param name="enumType">给定枚举类型</param>
    /// <param name="callback">对每一个Enum成员调用的回调函数</param>
    public static void ReadEnumMembers(Type enumType, Action<EnumMemberInfo> callback)
    {
        Debug.Assert(enumType.IsEnum, $"类型'{enumType.Name}'不是枚举类型。");

        string[] names = enumType.GetEnumNames();
        Array values = enumType.GetEnumValues();

        for (int i = 0; i < names.Length; i++)
        {
            var enumValue = values.GetValue(i);
            var enumField = enumType.GetField(names[i]);

            if (enumValue == null || enumField == null)
            {
                continue;
            }
                
            callback(new EnumMemberInfo
            {
                Name = names[i],
                Value = (int)enumValue,
                Field = enumField
            });
        }
    }

    /// <summary>
    ///     读取枚举类型各个成员的<see cref="DescriptionAttribute" />中定义的描述。
    /// </summary>
    /// <returns></returns>
    public static Dictionary<string, int> ReadEnumMembersDescription(Type type)
    {
        var description = new Dictionary<string, int>();

        ReadEnumMembers(type, info =>
        {
            var descAttr = info.Field.GetCustomAttribute<DescriptionAttribute>();

            if (descAttr == null)
            {
                return;
            }

            Debug.Assert(!string.IsNullOrEmpty(descAttr.Description),
                $"枚举'{type.Name}'的成员'{info.Name}'描述是空字符。");
            Debug.Assert(!description.ContainsKey(descAttr.Description),
                $"枚举'{type.Name}'的成员'{info.Name}'描述'{descAttr.Description}'已存在。");
            description.Add(descAttr.Description, info.Value);
        });

        return description;
    }

    /// <summary>
    ///     读取枚举类型各个成员的<see cref="DescriptionAttribute" />中定义的描述。
    /// </summary>
    /// <returns></returns>
    public static Dictionary<string, T> ReadEnumMembersDescription<T>() where T : Enum
    {
        Type enumType = typeof(T);
        var description = new Dictionary<string, T>();

        ReadEnumMembers(enumType, info =>
        {
            var descAttr = info.Field.GetCustomAttribute<DescriptionAttribute>();

            if (descAttr == null)
            {
                return;
            }

            Debug.Assert(!string.IsNullOrEmpty(descAttr.Description),
                $"枚举'{enumType.Name}'的成员'{info.Name}'描述是空字符。");
            Debug.Assert(!description.ContainsKey(descAttr.Description),
                $"枚举'{enumType.Name}'的成员'{info.Name}'描述'{descAttr.Description}'已存在。");
            description.Add(descAttr.Description, (T)Enum.ToObject(enumType, info.Value));
        });

        return description;
    }

    /// <summary>
    ///     读取枚举类型成员，并将成员中带有<see cref="DescriptionAttribute" />特性的描述添加进列表中。
    /// </summary>
    /// <param name="specialValue">特殊枚举值</param>
    /// <param name="specialDescription">
    ///     特殊枚举值的<see cref="DescriptionAttribute.Description" />值，如果不包含指定值
    ///     或者指定值不带有<see cref="DescriptionAttribute" />特性，此值将为<see cref="string.Empty" />
    /// </param>
    /// <returns>枚举成员<see cref="DescriptionAttribute.Description" />值列表</returns>
    public static Dictionary<string, T> ReadEnumMembersDescription<T>(int specialValue,
        out string specialDescription)
        where T : Enum
    {
        string special = string.Empty;

        Type enumType = typeof(T);
        var description = new Dictionary<string, T>();

        ReadEnumMembers(enumType, info =>
        {
            var descAttr = info.Field.GetCustomAttribute<DescriptionAttribute>();

            if (descAttr == null)
            {
                return;
            }

            Debug.Assert(!string.IsNullOrEmpty(descAttr.Description),
                $"枚举'{enumType.Name}'的成员'{info.Name}'描述是空字符。");
            Debug.Assert(!description.ContainsKey(descAttr.Description),
                $"枚举'{enumType.Name}'的成员'{info.Name}'描述'{descAttr.Description}'已存在。");
            description.Add(descAttr.Description, (T)Enum.ToObject(enumType, info.Value));
            if (info.Value == specialValue)
            {
                special = descAttr.Description;
            }
        });

        specialDescription = special;

        return description;
    }

    public struct EnumMemberInfo
    {
        /// <summary>
        ///     枚举成员名
        /// </summary>
        public string Name;

        /// <summary>
        ///     枚举成员值
        /// </summary>
        public int Value;

        /// <summary>
        ///     枚举成员类型信息
        /// </summary>
        public FieldInfo Field;
    }
}